{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from keras.models import Model, Sequential\n",
    "from keras.layers import Input, Convolution2D, ZeroPadding2D, MaxPooling2D, Flatten, Dense, Dropout, Activation\n",
    "from keras.preprocessing.image import load_img, save_img, img_to_array\n",
    "from keras.applications.imagenet_utils import preprocess_input\n",
    "from keras.preprocessing import image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Base Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "if True:\n",
    "    model = Sequential()\n",
    "    model.add(ZeroPadding2D((1,1),input_shape=(224,224, 3)))\n",
    "    model.add(Convolution2D(64, (3, 3), name= 'conv1_1'))\n",
    "    model.add(Activation('relu', name='relu1_1'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(64, (3, 3), name= 'conv1_2'))\n",
    "    model.add(Activation('relu', name='relu1_2'))\n",
    "    model.add(MaxPooling2D((2,2), strides=(2,2), name='pool1'))\n",
    "\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(128, (3, 3), name= 'conv2_1'))\n",
    "    model.add(Activation('relu', name='relu2_1'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(128, (3, 3), name= 'conv2_2'))\n",
    "    model.add(Activation('relu', name='relu2_2'))\n",
    "    model.add(MaxPooling2D((2,2), strides=(2,2), name='pool2'))\n",
    "\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(256, (3, 3), name= 'conv3_1'))\n",
    "    model.add(Activation('relu', name='relu3_1'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(256, (3, 3), name= 'conv3_2'))\n",
    "    model.add(Activation('relu', name='relu3_2'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(256, (3, 3), name= 'conv3_3'))\n",
    "    model.add(Activation('relu', name='relu3_3'))\n",
    "    model.add(MaxPooling2D((2,2), strides=(2,2), name='pool3'))\n",
    "\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv4_1'))\n",
    "    model.add(Activation('relu', name='relu4_1'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv4_2'))\n",
    "    model.add(Activation('relu', name='relu4_2'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv4_3'))\n",
    "    model.add(Activation('relu', name='relu4_3'))\n",
    "    model.add(MaxPooling2D((2,2), strides=(2,2), name='pool4'))\n",
    "\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv5_1'))\n",
    "    model.add(Activation('relu', name='relu5_1'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv5_2'))\n",
    "    model.add(Activation('relu', name='relu5_2'))\n",
    "    model.add(ZeroPadding2D((1,1)))\n",
    "    model.add(Convolution2D(512, (3, 3), name= 'conv5_3'))\n",
    "    model.add(Activation('relu', name='relu5_3'))\n",
    "    model.add(MaxPooling2D((2,2), strides=(2,2), name='pool5'))\n",
    "\n",
    "    model.add(Convolution2D(4096, (7, 7), name= 'fc6'))\n",
    "    model.add(Activation('relu', name='relu6'))\n",
    "    model.add(Dropout(0.5, name='dropout6'))\n",
    "    model.add(Convolution2D(4096, (1, 1), name= 'fc7'))\n",
    "    model.add(Activation('relu', name='relu7'))\n",
    "    model.add(Dropout(0.5, name='dropout7'))\n",
    "    model.add(Convolution2D(2622, (1, 1), name= 'fc8'))\n",
    "    model.add(Activation('relu'))\n",
    "    model.add(Flatten())\n",
    "    model.add(Activation('softmax', name= 'softmax'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MatConvNet to Keras"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.io import loadmat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = loadmat('vgg_face.mat', matlab_compatible=False, struct_as_record=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'__globals__': [],\n",
       " '__header__': b'MATLAB 5.0 MAT-file, Platform: MACI64, Created on: Tue Oct 13 16:54:01 2015',\n",
       " '__version__': '1.0',\n",
       " 'net': array([[<scipy.io.matlab.mio5_params.mat_struct object at 0x00000208ACA1D1D0>]],\n",
       "       dtype=object)}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = data['net'][0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "ref_model_layers = net.layers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 39)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ref_model_layers.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "ref_model_layers = ref_model_layers[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['conv1_1']\n",
      "['relu1_1']\n",
      "['conv1_2']\n",
      "['relu1_2']\n",
      "['pool1']\n",
      "['conv2_1']\n",
      "['relu2_1']\n",
      "['conv2_2']\n",
      "['relu2_2']\n",
      "['pool2']\n",
      "['conv3_1']\n",
      "['relu3_1']\n",
      "['conv3_2']\n",
      "['relu3_2']\n",
      "['conv3_3']\n",
      "['relu3_3']\n",
      "['pool3']\n",
      "['conv4_1']\n",
      "['relu4_1']\n",
      "['conv4_2']\n",
      "['relu4_2']\n",
      "['conv4_3']\n",
      "['relu4_3']\n",
      "['pool4']\n",
      "['conv5_1']\n",
      "['relu5_1']\n",
      "['conv5_2']\n",
      "['relu5_2']\n",
      "['conv5_3']\n",
      "['relu5_3']\n",
      "['pool5']\n",
      "['fc6']\n",
      "['relu6']\n",
      "['dropout6']\n",
      "['fc7']\n",
      "['relu7']\n",
      "['dropout7']\n",
      "['fc8']\n",
      "['softmax']\n"
     ]
    }
   ],
   "source": [
    "for layer in ref_model_layers:\n",
    "    print(layer[0][0].name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_of_ref_model_layers = ref_model_layers.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "base_model_layer_names = [layer.name for layer in model.layers]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1_1 :  (3, 3, 3, 64)\n",
      "conv1_2 :  (3, 3, 64, 64)\n",
      "conv2_1 :  (3, 3, 64, 128)\n",
      "conv2_2 :  (3, 3, 128, 128)\n",
      "conv3_1 :  (3, 3, 128, 256)\n",
      "conv3_2 :  (3, 3, 256, 256)\n",
      "conv3_3 :  (3, 3, 256, 256)\n",
      "conv4_1 :  (3, 3, 256, 512)\n",
      "conv4_2 :  (3, 3, 512, 512)\n",
      "conv4_3 :  (3, 3, 512, 512)\n",
      "conv5_1 :  (3, 3, 512, 512)\n",
      "conv5_2 :  (3, 3, 512, 512)\n",
      "conv5_3 :  (3, 3, 512, 512)\n",
      "fc6 :  (7, 7, 512, 4096)\n",
      "fc7 :  (1, 1, 4096, 4096)\n",
      "fc8 :  (1, 1, 4096, 2622)\n"
     ]
    }
   ],
   "source": [
    "for layer in model.layers:\n",
    "    layer_name = layer.name\n",
    "    try:\n",
    "        print(layer_name,\": \",layer.weights[0].shape)\n",
    "    except:\n",
    "        print(\"\",end='')\n",
    "        #print(layer_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1_1 :  (3, 3, 3, 64)\n",
      "conv1_2 :  (3, 3, 64, 64)\n",
      "conv2_1 :  (3, 3, 64, 128)\n",
      "conv2_2 :  (3, 3, 128, 128)\n",
      "conv3_1 :  (3, 3, 128, 256)\n",
      "conv3_2 :  (3, 3, 256, 256)\n",
      "conv3_3 :  (3, 3, 256, 256)\n",
      "conv4_1 :  (3, 3, 256, 512)\n",
      "conv4_2 :  (3, 3, 512, 512)\n",
      "conv4_3 :  (3, 3, 512, 512)\n",
      "conv5_1 :  (3, 3, 512, 512)\n",
      "conv5_2 :  (3, 3, 512, 512)\n",
      "conv5_3 :  (3, 3, 512, 512)\n",
      "fc6 :  (7, 7, 512, 4096)\n",
      "fc7 :  (1, 1, 4096, 4096)\n",
      "fc8 :  (1, 1, 4096, 2622)\n"
     ]
    }
   ],
   "source": [
    "for i in range(num_of_ref_model_layers):\n",
    "    ref_model_layer = ref_model_layers[i][0,0].name[0]\n",
    "    \n",
    "    try:\n",
    "        weights = ref_model_layers[i][0,0].weights[0,0]\n",
    "        print(ref_model_layer,\": \",weights.shape)\n",
    "    except:\n",
    "        #print(ref_model_layer)\n",
    "        print(\"\",end='')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 .  conv1_1\n",
      "2 .  conv1_2\n",
      "5 .  conv2_1\n",
      "7 .  conv2_2\n",
      "10 .  conv3_1\n",
      "12 .  conv3_2\n",
      "14 .  conv3_3\n",
      "17 .  conv4_1\n",
      "19 .  conv4_2\n",
      "21 .  conv4_3\n",
      "24 .  conv5_1\n",
      "26 .  conv5_2\n",
      "28 .  conv5_3\n",
      "31 .  fc6\n",
      "34 .  fc7\n",
      "37 .  fc8\n"
     ]
    }
   ],
   "source": [
    "for i in range(num_of_ref_model_layers):\n",
    "    ref_model_layer = ref_model_layers[i][0,0].name[0]\n",
    "    if ref_model_layer in base_model_layer_names:\n",
    "        #we just need to set convolution and fully connected weights\n",
    "        if ref_model_layer.find(\"conv\") == 0 or ref_model_layer.find(\"fc\") == 0:\n",
    "            print(i,\". \",ref_model_layer)\n",
    "            base_model_index = base_model_layer_names.index(ref_model_layer)\n",
    "            \n",
    "            weights = ref_model_layers[i][0,0].weights[0,0]\n",
    "            bias = ref_model_layers[i][0,0].weights[0,1]\n",
    "            \n",
    "            model.layers[base_model_index].set_weights([weights, bias[:,0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save_weights('vgg-face-weights.h5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Constructing reference model with clues"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "\n",
    "for i in range(num_of_ref_model_layers):\n",
    "    ref_model_layer = ref_model_layers[i][0][0].name[0]\n",
    "    if ref_model_layer.find(\"conv\") == 0 or ref_model_layer.find(\"fc\") == 0:\n",
    "        weights = ref_model_layers[i][0,0].weights\n",
    "        weights_shape = weights[0][0].shape\n",
    "        #print(\":\", weights_shape)\n",
    "        filter_x = weights_shape[0]; filter_y = weights_shape[1]\n",
    "        number_of_filters = weights_shape[3]\n",
    "        \n",
    "        if ref_model_layer.find(\"conv\") == 0:\n",
    "            print(\"ZeroPadding2D((1,1))\")\n",
    "            if i == 0:\n",
    "                model.add(ZeroPadding2D((1,1),input_shape=(224,224, 3)))\n",
    "            else:\n",
    "                model.add(ZeroPadding2D((1,1)))\n",
    "        \n",
    "        print(\"Convolution2D(\",number_of_filters,\", (\",filter_x,\", \",filter_y,\"), name='\",ref_model_layer,\"')\")\n",
    "        model.add(Convolution2D(number_of_filters, (filter_x, filter_y), name= ref_model_layer))\n",
    "        \n",
    "    else:\n",
    "        if ref_model_layer.find(\"relu\") == 0:\n",
    "            print(\"Activation('relu', name=\",ref_model_layer)\n",
    "            model.add(Activation('relu', name=ref_model_layer))\n",
    "        elif ref_model_layer.find(\"dropout\") == 0:\n",
    "            print(\"Dropout(0.5, name=\",ref_model_layer,\")\")\n",
    "            model.add(Dropout(0.5, name=ref_model_layer))\n",
    "        elif ref_model_layer.find(\"pool\") == 0:\n",
    "            print(\"MaxPooling2D((2,2), strides=(2,2), name=\",ref_model_layer,\")\")\n",
    "            model.add(MaxPooling2D((2,2), strides=(2,2), name=ref_model_layer))\n",
    "        elif ref_model_layer.find(\"softmax\") == 0:\n",
    "            print(\"Activation('softmax', name=\",ref_model_layer,\")\")\n",
    "            model.add(Activation('softmax', name=ref_model_layer))\n",
    "        else:\n",
    "            print(\"-->\",ref_model_layer)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
